#include "wx/wxprec.h"
#include "wx/richtext/richtextformatdlg.h"
#include "wx/bookctrl.h"
#include "wx/colordlg.h"
#include "wx/settings.h"
#include "wx/module.h"
#include "wx/imaglist.h"
#include "wx/richtext/richtextctrl.h"
#include "wx/richtext/richtextstyles.h"
#include "richtextfontpage.cpp"
#include "richtextindentspage.cpp"
#include "richtexttabspage.cpp"
#include "richtextbulletspage.cpp"

#ifndef __DMC__
#include "richtextliststylepage.cpp"
#endif

#include "richtextstylepage.cpp"

#define wxRICHTEXT_USE_TOOLBOOK false

bool wxRichTextFormattingDialog::sm_showToolTips = false;

IMPLEMENT_CLASS( wxRichTextFormattingDialog, wxPropertySheetDialog )

BEGIN_EVENT_TABLE( wxRichTextFormattingDialog, wxPropertySheetDialog )
  EVT_BOOKCTRL_PAGE_CHANGED( wxID_ANY, wxRichTextFormattingDialog::OnTabChanged )
END_EVENT_TABLE()

wxRichTextFormattingDialogFactory* wxRichTextFormattingDialog::ms_FormattingDialogFactory = NULL;

void wxRichTextFormattingDialog::Init() {
  m_imageList = NULL;
  m_styleDefinition = NULL;
  m_styleSheet = NULL;
}

wxRichTextFormattingDialog::~wxRichTextFormattingDialog() {
  delete m_imageList;
  delete m_styleDefinition;
}

bool wxRichTextFormattingDialog::Create( long flags, wxWindow* parent, const wxString& title, wxWindowID id, const wxPoint& pos, const wxSize& sz, long style ) {
  SetExtraStyle( wxDIALOG_EX_CONTEXTHELP | wxWS_EX_VALIDATE_RECURSIVELY );
  int resizeBorder = wxRESIZE_BORDER;
  GetFormattingDialogFactory()->SetSheetStyle( this );
  wxPropertySheetDialog::Create( parent, id, title, pos, sz, style | ( int )wxPlatform::IfNot( wxOS_WINDOWS_CE, resizeBorder ) );
  GetFormattingDialogFactory()->CreateButtons( this );
  GetFormattingDialogFactory()->CreatePages( flags, this );
  LayoutDialog();
  return true;
}

bool wxRichTextFormattingDialog::GetStyle( wxRichTextCtrl* ctrl, const wxRichTextRange& range ) {
  if( ctrl->GetBuffer().GetStyleForRange( range.ToInternal(), m_attributes ) ) {
    return UpdateDisplay();
  } else
  { return false; }
}

bool wxRichTextFormattingDialog::ApplyStyle( wxRichTextCtrl* ctrl, const wxRichTextRange& range, int flags ) {
  return ctrl->SetStyleEx( range, m_attributes, flags );
}

bool wxRichTextFormattingDialog::SetStyle( const wxTextAttrEx& style, bool update ) {
  m_attributes = style;
  if( update ) {
    UpdateDisplay();
  }
  return true;
}

bool wxRichTextFormattingDialog::SetStyleDefinition( const wxRichTextStyleDefinition& styleDef, wxRichTextStyleSheet* sheet, bool update ) {
  m_styleSheet = sheet;
  if( m_styleDefinition ) {
    delete m_styleDefinition;
  }
  m_styleDefinition = styleDef.Clone();
  return SetStyle( m_styleDefinition->GetStyle(), update );
}

bool wxRichTextFormattingDialog::TransferDataToWindow() {
  if( m_styleDefinition ) {
    m_attributes = m_styleDefinition->GetStyle();
  }
  if( !wxPropertySheetDialog::TransferDataToWindow() ) {
    return false;
  }
  return true;
}

bool wxRichTextFormattingDialog::TransferDataFromWindow() {
  if( !wxPropertySheetDialog::TransferDataFromWindow() ) {
    return false;
  }
  if( m_styleDefinition ) {
    m_styleDefinition->GetStyle() = m_attributes;
  }
  return true;
}

/// Update the display
bool wxRichTextFormattingDialog::UpdateDisplay() {
  return TransferDataToWindow();
}

void wxRichTextFormattingDialog::OnTabChanged( wxBookCtrlEvent& event ) {
  if( GetBookCtrl() != event.GetEventObject() ) {
    event.Skip();
    return;
  }
  int oldPageId = event.GetOldSelection();
  if( oldPageId != -1 ) {
    wxWindow* page = GetBookCtrl()->GetPage( oldPageId );
    if( page ) {
      page->TransferDataFromWindow();
    }
  }
  int pageId = event.GetSelection();
  if( pageId != -1 ) {
    wxWindow* page = GetBookCtrl()->GetPage( pageId );
    if( page ) {
      page->TransferDataToWindow();
    }
  }
}

void wxRichTextFormattingDialog::OnHelp( wxCommandEvent& event ) {
  int selPage = GetBookCtrl()->GetSelection();
  if( selPage != wxNOT_FOUND ) {
    int pageId = m_pageIds[selPage];
    if( !GetFormattingDialogFactory()->ShowHelp( pageId, this ) ) {
      event.Skip();
    }
  }
}

void wxRichTextFormattingDialog::SetFormattingDialogFactory( wxRichTextFormattingDialogFactory* factory ) {
  if( ms_FormattingDialogFactory ) {
    delete ms_FormattingDialogFactory;
  }
  ms_FormattingDialogFactory = factory;
}

bool wxRichTextFormattingDialogFactory::CreatePages( long pages, wxRichTextFormattingDialog* dialog ) {
  if( dialog->GetImageList() ) {
    dialog->GetBookCtrl()->SetImageList( dialog->GetImageList() );
  }
  int availablePageCount = GetPageIdCount();
  int i;
  bool selected = false;
  for( i = 0; i < availablePageCount; i ++ ) {
    int pageId = GetPageId( i );
    if( pageId != -1 && ( pages & pageId ) ) {
      wxString title;
      wxPanel* panel = CreatePage( pageId, title, dialog );
      wxASSERT( panel != NULL );
      if( panel ) {
        int imageIndex = GetPageImage( pageId );
        dialog->GetBookCtrl()->AddPage( panel, title, !selected, imageIndex );
        selected = true;
        dialog->AddPageId( pageId );
      }
    }
  }
  return true;
}

wxPanel* wxRichTextFormattingDialogFactory::CreatePage( int page, wxString& title, wxRichTextFormattingDialog* dialog ) {
  if( page == wxRICHTEXT_FORMAT_STYLE_EDITOR ) {
    wxRichTextStylePage* page = new wxRichTextStylePage( dialog->GetBookCtrl(), wxID_ANY );
    title = _( "Style" );
    return page;
  } else if( page == wxRICHTEXT_FORMAT_FONT ) {
    wxRichTextFontPage* page = new wxRichTextFontPage( dialog->GetBookCtrl(), wxID_ANY );
    title = _( "Font" );
    return page;
  } else if( page == wxRICHTEXT_FORMAT_INDENTS_SPACING ) {
    wxRichTextIndentsSpacingPage* page = new wxRichTextIndentsSpacingPage( dialog->GetBookCtrl(), wxID_ANY );
    title = _( "Indents && Spacing" );
    return page;
  } else if( page == wxRICHTEXT_FORMAT_TABS ) {
    wxRichTextTabsPage* page = new wxRichTextTabsPage( dialog->GetBookCtrl(), wxID_ANY );
    title = _( "Tabs" );
    return page;
  } else if( page == wxRICHTEXT_FORMAT_BULLETS ) {
    wxRichTextBulletsPage* page = new wxRichTextBulletsPage( dialog->GetBookCtrl(), wxID_ANY );
    title = _( "Bullets" );
    return page;
  }
  #ifndef __DMC__
  else if( page == wxRICHTEXT_FORMAT_LIST_STYLE ) {
    wxRichTextListStylePage* page = new wxRichTextListStylePage( dialog->GetBookCtrl(), wxID_ANY );
    title = _( "List Style" );
    return page;
  }
  #endif
  else
  { return NULL; }
}

int wxRichTextFormattingDialogFactory::GetPageId( int i ) const {
  int pages[] = {
    wxRICHTEXT_FORMAT_STYLE_EDITOR,
    wxRICHTEXT_FORMAT_FONT,
    wxRICHTEXT_FORMAT_INDENTS_SPACING,
    wxRICHTEXT_FORMAT_BULLETS,
    wxRICHTEXT_FORMAT_TABS,
    wxRICHTEXT_FORMAT_LIST_STYLE
  };
  if( i < 0 || i > 5 ) {
    return -1;
  }
  return pages[i];
}

int wxRichTextFormattingDialogFactory::GetPageIdCount() const {
  #ifdef __DMC__
  return 5;
  #else
  return 6;
  #endif
}

bool wxRichTextFormattingDialogFactory::SetSheetStyle( wxRichTextFormattingDialog* dialog ) {
  bool useToolBook = wxRICHTEXT_USE_TOOLBOOK;
  if( useToolBook ) {
    int sheetStyle = wxPROPSHEET_SHRINKTOFIT;
    sheetStyle |= wxPROPSHEET_TOOLBOOK;
    dialog->SetSheetStyle( sheetStyle );
    dialog->SetSheetInnerBorder( 0 );
    dialog->SetSheetOuterBorder( 0 );
  }
  return true;
}

bool wxRichTextFormattingDialogFactory::CreateButtons( wxRichTextFormattingDialog* dialog ) {
  bool useToolBook = wxRICHTEXT_USE_TOOLBOOK;
  int flags = wxOK | wxCANCEL;
  if( dialog->GetWindowStyleFlag() & wxRICHTEXT_FORMAT_HELP_BUTTON ) {
    flags |= wxHELP;
  }
  if( !useToolBook ) {
    dialog->CreateButtons( flags );
  }
  return true;
}

class wxRichTextFormattingDialogModule: public wxModule {
    DECLARE_DYNAMIC_CLASS( wxRichTextFormattingDialogModule )
  public:
    wxRichTextFormattingDialogModule() {}
    bool OnInit() { wxRichTextFormattingDialog::SetFormattingDialogFactory( new wxRichTextFormattingDialogFactory ); return true; }
    void OnExit() { wxRichTextFormattingDialog::SetFormattingDialogFactory( NULL ); }
};

IMPLEMENT_DYNAMIC_CLASS( wxRichTextFormattingDialogModule, wxModule )
BEGIN_EVENT_TABLE( wxRichTextFontPreviewCtrl, wxWindow )
  EVT_PAINT( wxRichTextFontPreviewCtrl::OnPaint )
END_EVENT_TABLE()

void wxRichTextFontPreviewCtrl::OnPaint( wxPaintEvent& ( event ) ) {
  wxPaintDC dc( this );
  wxSize size = GetSize();
  wxFont font = GetFont();
  if( ( GetTextEffects() & wxTEXT_ATTR_EFFECT_SUPERSCRIPT ) || ( GetTextEffects() & wxTEXT_ATTR_EFFECT_SUBSCRIPT ) ) {
    double size = static_cast<double>( font.GetPointSize() ) / wxSCRIPT_MUL_FACTOR;
    font.SetPointSize( static_cast<int>( size ) );
  }
  if( font.Ok() ) {
    dc.SetFont( font );
    long w = 0, h = 0;
    wxString text( _( "ABCDEFGabcdefg12345" ) );
    if( GetTextEffects() & wxTEXT_ATTR_EFFECT_CAPITALS ) {
      text.MakeUpper();
    }
    dc.GetTextExtent( text, &w, &h );
    int cx = wxMax( 2, ( size.x / 2 ) - ( w / 2 ) );
    int cy = wxMax( 2, ( size.y / 2 ) - ( h / 2 ) );
    if( GetTextEffects() & wxTEXT_ATTR_EFFECT_SUPERSCRIPT ) {
      cy -= h / 2;
    }
    if( GetTextEffects() & wxTEXT_ATTR_EFFECT_SUBSCRIPT ) {
      cy += h / 2;
    }
    dc.SetTextForeground( GetForegroundColour() );
    dc.SetClippingRegion( 2, 2, size.x - 4, size.y - 4 );
    dc.DrawText( text, cx, cy );
    if( GetTextEffects() & wxTEXT_ATTR_EFFECT_STRIKETHROUGH ) {
      dc.SetPen( wxPen( GetForegroundColour(), 1 ) );
      dc.DrawLine( cx, ( int )( cy + h / 2 + 0.5 ), cx + w, ( int )( cy + h / 2 + 0.5 ) );
    }
    dc.DestroyClippingRegion();
  }
}

wxRichTextFormattingDialog* wxRichTextFormattingDialog::GetDialog( wxWindow* win ) {
  wxWindow* p = win->GetParent();
  while( p && !p->IsKindOf( CLASSINFO( wxRichTextFormattingDialog ) ) ) {
    p = p->GetParent();
  }
  wxRichTextFormattingDialog* dialog = wxDynamicCast( p, wxRichTextFormattingDialog );
  return dialog;
}

wxTextAttrEx* wxRichTextFormattingDialog::GetDialogAttributes( wxWindow* win ) {
  wxRichTextFormattingDialog* dialog = GetDialog( win );
  if( dialog ) {
    return & dialog->GetAttributes();
  } else
  { return NULL; }
}

wxRichTextStyleDefinition* wxRichTextFormattingDialog::GetDialogStyleDefinition( wxWindow* win ) {
  wxRichTextFormattingDialog* dialog = GetDialog( win );
  if( dialog ) {
    return dialog->GetStyleDefinition();
  } else
  { return NULL; }
}

BEGIN_EVENT_TABLE( wxRichTextColourSwatchCtrl, wxControl )
  EVT_MOUSE_EVENTS( wxRichTextColourSwatchCtrl::OnMouseEvent )
END_EVENT_TABLE()

IMPLEMENT_CLASS( wxRichTextColourSwatchCtrl, wxControl )

wxRichTextColourSwatchCtrl::wxRichTextColourSwatchCtrl( wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style ) {
  if( ( style & wxBORDER_MASK ) == wxBORDER_DEFAULT ) {
    style |= wxBORDER_SUNKEN;
  }
  wxControl::Create( parent, id, pos, size, style );
  SetColour( wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW ) );
}

wxRichTextColourSwatchCtrl::~wxRichTextColourSwatchCtrl() {
}

void wxRichTextColourSwatchCtrl::OnMouseEvent( wxMouseEvent& event ) {
  if( event.LeftDown() ) {
    wxWindow* parent = GetParent();
    while( parent != NULL && !parent->IsKindOf( CLASSINFO( wxDialog ) ) && !parent->IsKindOf( CLASSINFO( wxFrame ) ) ) {
      parent = parent->GetParent();
    }
    wxColourData data;
    data.SetChooseFull( true );
    data.SetColour( m_colour );
    #if wxUSE_COLOURDLG
    wxColourDialog *dialog = new wxColourDialog( parent, &data );
    dialog->SetTitle( _( "Colour" ) );
    if( dialog->ShowModal() == wxID_OK ) {
      wxColourData retData = dialog->GetColourData();
      m_colour = retData.GetColour();
      SetBackgroundColour( m_colour );
    }
    dialog->Destroy();
    #endif
    Refresh();
    wxCommandEvent event( wxEVT_COMMAND_BUTTON_CLICKED, GetId() );
    GetEventHandler()->ProcessEvent( event );
  }
}

IMPLEMENT_CLASS( wxRichTextFontListBox, wxHtmlListBox )

BEGIN_EVENT_TABLE( wxRichTextFontListBox, wxHtmlListBox )
END_EVENT_TABLE()

wxRichTextFontListBox::wxRichTextFontListBox( wxWindow* parent, wxWindowID id, const wxPoint& pos,
    const wxSize& size, long style ) {
  if( ( style & wxBORDER_MASK ) == wxBORDER_DEFAULT ) {
    style |= wxBORDER_SUNKEN;
  }
  Init();
  Create( parent, id, pos, size, style );
}

bool wxRichTextFontListBox::Create( wxWindow* parent, wxWindowID id, const wxPoint& pos,
                                    const wxSize& size, long style ) {
  return wxHtmlListBox::Create( parent, id, pos, size, style );
}

wxRichTextFontListBox::~wxRichTextFontListBox() {
}

wxString wxRichTextFontListBox::OnGetItem( size_t n ) const {
  if( m_faceNames.GetCount() == 0 ) {
    return wxEmptyString;
  }
  wxString str = CreateHTML( m_faceNames[n] );
  return str;
}

wxString wxRichTextFontListBox::GetFaceName( size_t i ) const {
  return m_faceNames[i];
}

int wxRichTextFontListBox::SetFaceNameSelection( const wxString& name ) {
  int i = m_faceNames.Index( name );
  SetSelection( i );
  return i;
}

void wxRichTextFontListBox::UpdateFonts() {
  wxArrayString facenames = wxRichTextCtrl::GetAvailableFontNames();
  m_faceNames = facenames;
  m_faceNames.Sort();
  SetItemCount( m_faceNames.GetCount() );
  Refresh();
}

wxString wxRichTextFontListBox::CreateHTML( const wxString& facename ) const {
  wxString str = wxT( "<font" );
  str << wxT( " size=\"+2\"" );;
  if( !facename.IsEmpty() && facename != _( "(none)" ) ) {
    str << wxT( " face=\"" ) << facename << wxT( "\"" );
  }
  str << wxT( ">" );
  bool hasBold = false;
  if( hasBold ) {
    str << wxT( "<b>" );
  }
  str += facename;
  if( hasBold ) {
    str << wxT( "</b>" );
  }
  str << wxT( "</font>" );
  return str;
}
